package com.xqboss.apps.service.sys;


import com.xqboss.apps.constant.LockKey;
import com.xqboss.apps.domain.user.*;
import com.xqboss.apps.dto.user.HotBeansGiveDto;
import com.xqboss.apps.enums.user.WalletChangeDirectionEnum;
import com.xqboss.apps.enums.user.WalletLidouChangeTypeEnum;
import com.xqboss.apps.service.user.UserAssetLidouService;
import com.xqboss.apps.service.user.UserIdentityPermLidouService;
import com.xqboss.apps.service.user.UserIdentityService;
import com.xqboss.common.constant.CacheConstants;
import com.xqboss.common.constant.HttpStatus;
import com.xqboss.common.core.domain.entity.SysUser;
import com.xqboss.common.core.redis.RedisCache;
import com.xqboss.common.core.redis.lock.LockValue;
import com.xqboss.common.core.redis.lock.RedisLock;
import com.xqboss.common.exception.ServiceException;
import com.xqboss.common.utils.TransactionalManage;
import com.xqboss.system.service.ISysUserService;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xqboss.apps.domain.sys.SysUserLidouRecord;
import com.xqboss.apps.mapper.sys.SysUserLidouRecordMapper;

import java.math.BigDecimal;
import java.math.RoundingMode;


/**
 * 力豆转增记录表(SysUserLidouRecord)表服务实现类
 *
 * @author makejava
 * @since 2024-03-08 15:49:47
 */
@Service
public class SysUserLidouRecordService extends ServiceImpl<SysUserLidouRecordMapper, SysUserLidouRecord> {


    @Autowired
    private UserIdentityService userIdentityService;

    @Autowired
    private UserIdentityPermLidouService userIdentityPermLidouService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private UserAssetLidouService userAssetLidouService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private TransactionalManage transactionalManage;


    /**
     * 转赠
     * @param dto
     * @param userId
     */
    @SneakyThrows
    @RedisLock(lockKey = LockKey.LOCK_USER_WALLET)
    public void give(HotBeansGiveDto dto, @LockValue Long userId) {
        BigDecimal amount = dto.getAmount();
        // 获取转增用户每日最大转增次数
        Long identityId = userIdentityService.getByUserId(userId).getId();
        UserIdentityPermLidou permLidou = userIdentityPermLidouService.lambdaQuery()
                .eq(UserIdentityPermLidou::getIdentityId, identityId)
                .one();
        // 计算手续费
        BigDecimal decimal = new BigDecimal(permLidou.getFeeRate()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        // 手续费校验
        BigDecimal setScale = amount.multiply(decimal).setScale(2, RoundingMode.HALF_UP);
        if (setScale.compareTo(dto.getServiceCharge()) != 0) {
            throw new ServiceException("服务费有误,转赠失败");
        }
        // 实际支付校验
        BigDecimal add = amount.add(setScale).setScale(2, RoundingMode.HALF_UP);
        if (add.compareTo(dto.getRealQuantity()) != 0) {
            throw new ServiceException("支付费用有误,转赠失败");
        }
        // 每日最大次数
        Integer maxDailyTimes = permLidou.getMaxDailyTimes();
        // 该身份配置的最大和最小转增数量
        BigDecimal maxSingleAmount = permLidou.getMaxSingleAmount();
        BigDecimal minSingleAmount = permLidou.getMinSingleAmount();
        // 被赠用户身份判定
        SysUser sysUser = sysUserService.selectUserById(dto.getRecipientUserId());
        if (null == sysUser) {
            throw new ServiceException("被赠用户信息异常");
        }
        // 赠送人扳手钱包
        UserAssetLidou giveLidouWallet = userAssetLidouService.getLidouInfo(userId);
        // 赠送人余额
        BigDecimal giveWalletAmount = giveLidouWallet.getAmount();
        // 用户余额小于1则不可转增
        if (giveWalletAmount.compareTo(BigDecimal.valueOf(1)) < 0) {
            throw new ServiceException("余额不足1,不可转赠", HttpStatus.Insufficient_Balance);
        } else if (giveWalletAmount.compareTo(dto.getRealQuantity()) < 0) {
            throw new ServiceException("余额不足,不可转赠", HttpStatus.Insufficient_Balance);
        } else if (amount.compareTo(maxSingleAmount) > 0 || amount.compareTo(minSingleAmount) < 0) {
            throw new ServiceException("赠送数量不符合该身份最大或最小赠送量");
        }

        // 转赠次数
        Integer giveCount = redisCache.getCacheMapValue(CacheConstants.USER_LIDOU_COUNT_ALL_KEY, userId.toString());
        if (giveCount == null) {
            giveCount = 0;
        }
        if (giveCount >= maxDailyTimes) {
            throw new ServiceException("转赠次数不足,请明天再试", HttpStatus.insufficient_give_hot_beans);
        }

        // 添加记录
        SysUserLidouRecord record = new SysUserLidouRecord();
        record.setGiveUserId(userId);
        record.setRecipientUserId(dto.getRecipientUserId());
        record.setAmount(dto.getAmount());
        record.setServiceCharge(dto.getServiceCharge());

        transactionalManage.executeWithException(() -> {
            this.save(record);
            // 更新被赠人扳手余额
            userAssetLidouService.updateLidouBalance(dto.getRecipientUserId(), WalletLidouChangeTypeEnum.GIVE, WalletChangeDirectionEnum.IN, amount, record.getId(), WalletLidouChangeTypeEnum.GIVE.getMsg());
            // 更新赠送人扳手余额
            userAssetLidouService.updateLidouBalance(userId, WalletLidouChangeTypeEnum.GIVE, WalletChangeDirectionEnum.OUT, dto.getRealQuantity(), record.getId(), WalletLidouChangeTypeEnum.GIVE.getMsg());
            return true;
        });
        // 更新转赠次数
        redisCache.setCacheMapValue(CacheConstants.USER_LIDOU_COUNT_ALL_KEY, userId.toString(), giveCount + 1);
    }
}
